import java.util.ArrayList;
import java.util.HashMap;

import static java.lang.System.err;
import static java.lang.System.out;

public abstract class IterDeepDrawFixHM extends ComputerPlayer {
    protected static final Integer ZERO = Integer.valueOf(0);
    protected static final Integer ONE  = Integer.valueOf(1);

    protected HashMap<Board, Integer> boardHistory;

    public IterDeepDrawFixHM(boolean isBlack, Eval evaluator, int maxDepth) {
        super(isBlack, evaluator, maxDepth);
        boardHistory = new HashMap<Board, Integer>();
    }


    public abstract Board findMove(Board board, ArrayList<Board> moves,
                                   int depth);


    @Override
    public Action getMove(Board board, int moveNbr) {

        long startTime = System.currentTimeMillis();

        assert board.blackToMove == isBlack;


        ArrayList<Board> moves = board.generateMoves();
        Board bestMove = null;

        // Iterative deepening
        for( int depth = 1; depth <= searchDepth; depth++ ) {
            bestMove = findMove(board, moves, depth);
        }


        // Avoid draws
        int nOldPieces = BitUtils.countBits( board.black | board.white );
        int nOldKings  = BitUtils.countBits( board.kings );
        int nNewPieces = BitUtils.countBits( bestMove.black | bestMove.white );
        int nNewKings  = BitUtils.countBits( bestMove.kings );

        boolean piecesTaken = (nOldPieces - nNewPieces != 0);
        boolean wasCrowned  = (nOldKings - nNewKings != 0);

        if(piecesTaken || wasCrowned) {
            boardHistory.clear();
            //out.println("cleared");
        }
        Integer occurrences = boardHistory.get(bestMove);
        if( occurrences != null ) {
            int o = occurrences + 1;
            //out.println("Put board in boardHistory with a count of " + o);
            //GameEngine.printBoard(bestMove);
            boardHistory.put(bestMove, o);
        }
        else {
            //out.println("Put a new board in boardHistory with a count of 1");
            boardHistory.put(bestMove, ONE);
        }



        // Print the move
        int[] myMove;
        if (bestMove != null) {
            myMove = movePathFromBoards(board, bestMove);
            out.print("My move is " + moveNbr + ": " + myMove[0]);
            for (int i = 1; i < myMove.length; i++) {
                out.print(" - " + myMove[i]);
            }
            out.println();
        } else {
            out.println(color + " couldn't find any available moves.");
            myMove = new int[0];
        }



        // Add time spent and print the time
        long endTime = System.currentTimeMillis();
        long thisMove = endTime - startTime;
        spentTime += thisMove;
        float thisMoveTime = thisMove / 1000.0F;
        float totalTime = spentTime / 1000.0F;
        out.printf("This move took: %.2f s.\n", thisMoveTime);
        out.printf("Total spent time: %.2f s.\n", totalTime);


        return new Action(myMove, spentTime);
    }
}
